/**
 * @Author: douxuefeng
 * @Date: 2020/9/7 上午11:28
 * @File: pay
 * @Desc: 下单
 */
package pay

import (
	"encoding/xml"
	"errors"
	go_common "gitee.com/douxuefeng/go-common"
	"log"
	"strings"
)
const (
	baseUrl = "https://api.mch.weixin.qq.com/pay/"
	baseUrlSandBox = "https://api.mch.weixin.qq.com/sandboxnew/pay/"
	unifiedOrder = "unifiedorder"
)
type Order struct {
	*Config
}

func NewOrder(cfg *Config) *Order {
	return &Order{cfg}
}
// 统一下单
func (o *Order) UnifiedOrder(data *UnifiedOrder) (*UnifiedOrderResponse, error) {
	data.MchId = o.MchId
	data.Appid = o.AppId
	if !o.IsProd {
		data.TotalFee = 101
	}
	m, err := go_common.Struct2Map(data)
	if err != nil {
		return nil, err
	}
	url := baseUrl+unifiedOrder
	sign := strings.ToUpper(go_common.Md5(GetWechatPaySignString(m, o.Key)))
	var signkey string
	if !o.IsProd {
		url = baseUrlSandBox + unifiedOrder
		sdata := GetSignkey{
			MchId:    o.MchId,
			NonceStr: data.NonceStr,
			Sign:     sign,
		}
		sandboxdata, _ := xml.Marshal(sdata)
		signkeyMap := PostXml(baseUrlSandBox+"getsignkey", sandboxdata)
		var smap GetSignkeyResponse
		xml.Unmarshal(signkeyMap, &smap)

		if smap.ReturnCode == "SUCCESS" && smap.ReturnMsg == "ok" {
			signkey = smap.SandboxSignkey
		} else {
			return nil, errors.New("获取sandboxkey失败！")
		}
		sign = strings.ToUpper(go_common.Md5(GetWechatPaySignString(m, signkey)))
	}
	data.Sign =sign
	log.Println(data)
	xmldata, _ := xml.Marshal(data)
	rs := PostXml(url, xmldata)
	var res UnifiedOrderResponse
	err = xml.Unmarshal(rs, &res)
	log.Println(res)
	return &res, err
}

func (o *Order)QueryOrder(data *QueryOrder) (fee int, err error) {
	data.MchId = o.MchId
	data.Appid = o.AppId
	qmap, err := go_common.Struct2Map(data)
	delete(qmap, "json:")
	if err != nil {
		return 0,  err
	}
	var sign string
	sign = strings.ToUpper(go_common.Md5(GetWechatPaySignString(qmap, o.Key)))
	data.Sign = sign
	xmldata, err := xml.Marshal(data)
	if err != nil {
		return 0,  err
	}
	rs := PostXml(baseUrl+"orderquery", xmldata)
	var rmap QueryOrderResponse
	var ss map[string]interface{}
	xml.Unmarshal(rs, &ss)
	err = xml.Unmarshal(rs, &rmap)
	if err != nil {
		return
	}
	if rmap.ReturnCode == "SUCCESS" &&  rmap.ResultCode == "SUCCESS" && rmap.TradeState == "SUCCESS"  {
		return rmap.TotalFee, nil
	}
	return 0, errors.New("支付失败")
}

type UnifiedOrder struct {
	XMLName struct{} `xml:"xml"`
	Appid string `xml:"appid,omitempty" json:"appid,omitempty"`
	MchId string `xml:"mch_id,omitempty" json:"mch_id,omitempty"`
	DeviceInfo string `xml:"device_info,omitempty" json:"device_info,omitempty"`
	NonceStr string `xml:"nonce_str,omitempty" json:"nonce_str,omitempty"`
	Sign string `xml:"sign,omitempty" json:"sign,omitempty"`
	SignType string `xml:"sign_type,omitempty" json:"sign_type,omitempty"`
	Body string `xml:"body,omitempty" json:"body,omitempty"`
	Detail string `xml:"detail,omitempty" json:"detail,omitempty"`
	Attach string `xml:"attach,omitempty" json:"attach,omitempty"`
	OutTradeNo string `xml:"out_trade_no,omitempty" json:"out_trade_no,omitempty"`
	FeeType string `xml:"fee_type,omitempty" json:"fee_type,omitempty"`
	TotalFee int `xml:"total_fee,omitempty" json:"total_fee,omitempty"`
	SpbillCreateIp string `xml:"spbill_create_ip,omitempty" json:"spbill_create_ip,omitempty"`
	TimeStart string `xml:"time_start,omitempty" json:"time_start,omitempty"`
	TimeExpire string `xml:"time_expire,omitempty" json:"time_expire,omitempty"`
	GoodsTag string `xml:"goods_tag,omitempty" json:"goods_tag,omitempty"`
	NotifyUrl string `xml:"notify_url,omitempty" json:"notify_url,omitempty"`
	TradeType string `xml:"trade_type,omitempty" json:"trade_type,omitempty"`
	ProductId string `xml:"product_id,omitempty" json:"product_id,omitempty"`
	LimitPay string `xml:"limit_pay,omitempty" json:"limit_pay,omitempty"` //no_credit 禁用信用卡支付
	Openid string `xml:"openid,omitempty" json:"openid,omitempty"`
	Receipt string `xml:"receipt,omitempty" json:"receipt,omitempty"` // 电子发票 Y 微信发票功能
	SceneInfo string `xml:"scene_info,omitempty" json:"scene_info,omitempty"` // 支付场景
}
type UnifiedOrderResponse struct {
	Appid string `xml:"appid,omitempty" json:"appid,omitempty"`
	MchId string `xml:"mch_id,omitempty" json:"mch_id,omitempty"`
	DeviceInfo string `xml:"device_info,omitempty" json:"device_info,omitempty"`
	NonceStr string `xml:"nonce_str,omitempty" json:"nonce_str,omitempty"`
	Sign string `xml:"sign,omitempty" json:"sign,omitempty"`
	ReturnCode string `xml:"return_code,omitempty" json:"return_code,omitempty"`
	ReturnMsg string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
	ResultCode string `xml:"result_code,omitempty" json:"result_code,omitempty"`
	ErrCode string `xml:"err_code,omitempty" json:"err_code,omitempty"`
	ErrCodeDes string `xml:"err_code_des,omitempty" json:"err_code_des,omitempty"`
	TradeType string `xml:"trade_type,omitempty" json:"trade_type,omitempty"`
	PrepayId string `xml:"prepay_id,omitempty" json:"prepay_id,omitempty"`
	CodeUrl string `xml:"code_url,omitempty" json:"code_url,omitempty"`
}
type GetSignkey struct {
	XMLName struct{} `xml:"xml"`
	MchId string `xml:"mch_id,omitempty" json:"mch_id,omitempty"`
	NonceStr string `xml:"nonce_str,omitempty" json:"nonce_str,omitempty"`
	Sign string `xml:"sign,omitempty" json:"sign,omitempty"`
}
type GetSignkeyResponse struct {
	ReturnCode string `xml:"return_code"`
	ReturnMsg string `xml:"return_msg"`
	SandboxSignkey string `xml:"sandbox_signkey,omitempty"`
	MchId string `xml:"mch_id,omitempty"`
}

type QueryOrder struct {
	XMLName struct{} `xml:"xml" json:"-"`
	Appid string `xml:"appid" json:"appid"`
	MchId string `xml:"mch_id" json:"mch_id"`
	OutTradeNo string `xml:"out_trade_no" json:"out_trade_no"`
	NonceStr string `xml:"nonce_str" json:"nonce_str"`
	Sign string `xml:"sign" json:"json:"-"`
	SignType string `xml:"sign_type" json:"sign_type"`
}
type QueryOrderResponse struct {
	Appid string `xml:"appid,omitempty" json:"appid,omitempty"`
	MchId string `xml:"mch_id,omitempty" json:"mch_id,omitempty"`
	DeviceInfo string `xml:"device_info,omitempty" json:"device_info,omitempty"`
	NonceStr string `xml:"nonce_str,omitempty" json:"nonce_str,omitempty"`
	Sign string `xml:"sign,omitempty" json:"sign,omitempty"`
	ReturnCode string `xml:"return_code,omitempty" json:"return_code,omitempty"`
	ReturnMsg string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
	ResultCode string `xml:"result_code,omitempty" json:"result_code,omitempty"`
	ErrCode string `xml:"err_code,omitempty" json:"err_code,omitempty"`
	ErrCodeDes string `xml:"err_code_des,omitempty" json:"err_code_des,omitempty"`
	TradeType string `xml:"trade_type,omitempty" json:"trade_type,omitempty"`
	Openid string `xml:"openid,omitempty"`
	TradeState string `xml:"trade_state,omitemoty"`
	TotalFee int `xml:"total_fee,omitempty"`
}